
#include "dirOperations.h"
#include "fileHandling.h"
#include "hashtable.h"
#include "bst.h"

/*/////////////////////////////////////////////////////////////////////////////
~~~~~~~~~~~~~~~~~~~~~~~~~~~~//Function Definitions//~~~~~~~~~~~~~~~~~~~~~~~~~~
////////////////////////////////////////////////////////////////////////////*/



//Function to add directory as child of a directory if exists//

int makeDir(char *destDirPath, char* dirName) {

	// printf("Making Dir");
	long offset = 0;
	char *address = (char*) malloc(addressLength);
	directory* temp;

	if (mountStatus == unMounted) {
		printf("makedir_FAILURE %s\n", ERR_VFS_MAKEDIR_05);
		return makedir_FAILURE;
	}

	//INVALID_CHARACTER_IN_DIRNAME   //Invalid Char in dir name
	if (invalidChar(dirName, 0)) {
		printf("makedir_FAILURE %s\n", ERR_VFS_MAKEDIR_02);
		return makedir_FAILURE;
	}
	//check path, first char. must be /
	if (invalidChar(destDirPath, 1)) {
		printf("makedir_FAILURE %s\n", ERR_VFS_MAKEDIR_02);
		return makedir_FAILURE;
	}


	//file system full
	if (noOfFiles == noOfFileDescriptors) {
		printf("makedir_FAILURE %s\n", ERR_VFS_MAKEDIR_01);
		return makedir_FAILURE;
	}

	// printf("Dir to add : %s\n", dirName);
	strcpy(address, destDirPath);
	if (strcmp(destDirPath, "/") != 0)
		strcat(address, "/");
	strcat(address, dirName);

	//  printf("%s\n",address);

	if (head == NULL)
		initializeNAry(1);

	temp = creatNode(destDirPath, dirName, 'd', 0);
	if (temp != NULL) {

		if (strcmp(temp->name, dirName) != 0) {
			printf("makedir_FAILURE\n");
			return makedir_FAILURE;
		}

		offset = updateFileDescriptor(address, dirName, 'd', 0, 0);
		//    printf("Offset : %ld\n", offset);
		if (offset == -5) {
			deleteNode(temp);
			printf("makedir_FAILURE\n");
			return makedir_FAILURE;
		}
		temp->fileDescOffset = offset;

		insertFile(temp->name, offset);
		add_elt(findPath(temp));
		printf("makedir_SUCCESS\n");
		return makedir_SUCCESS;
	} else { // DIRECTORY_ALREADY_EXISTS
		// Dir with same name already exists
		printf("makedir_FAILURE %s\n", ERR_VFS_MAKEDIR_03);
		return makedir_FAILURE;
	}

}


// "dirToDelete" is name of directory to delete            

int deleteDir(char *pathOfDirToDelete) {

	//  printf("Deleting File");

	long offset = 0;
	iNode* inode = (iNode*) malloc(sizeof(iNode));
	inode->dirName = (char*) malloc(fileNameLength);

	if (mountStatus == unMounted) {
		printf("deletedir_FAILURE %s\n", ERR_VFS_DELETEDIR_04);
		return deletedir_FAILURE;
	}

	char* path = (char*) malloc(strlen(pathOfDirToDelete) + 5);
	strcpy(path, pathOfDirToDelete);
	char *name = getFileDirName(path);

	if (invalidChar(pathOfDirToDelete, 1)) {
		printf("deletedir_FAILURE %s\n", ERR_VFS_DELETEDIR_01);
		return deletedir_FAILURE;
	}

	if(strcmp(pathOfDirToDelete,"/")==0 && head!=NULL && head->child==NULL){
	head=NULL;
	printf("deletedir_SUCCESS\n");
		//	free(curDir);
		return deletedir_SUCCESS;
	}


	if (traceIPath(pathOfDirToDelete, inode) == NULL) {
		printf("deletedir_FAILURE %s\n", ERR_VFS_DELETEDIR_01);
		return deletedir_FAILURE;
	}

	directory* curDir = inode->parent;
	directory* parentDir;

	//printf(".%s.%s.",inode->parent->name,inode->dirName);

	if (curDir != NULL)
		parentDir = curDir->parent;
	else { // Path exists but directory does not, sm mistake in dirPath given
		printf("deletedir_FAILURE\n");
		return deletedir_FAILURE;
	}

	//CANNOT_FIND_SPECIFIED_PATH_OR_DIR         // Dir or path to dir, not exists
	if (strcmp(name, curDir->name) != 0) {
		printf("deletedir_FAILURE %s\n", ERR_VFS_DELETEDIR_01);
		return deletedir_FAILURE;
	}

	if (curDir->type != 'd') {
		printf("deletedir_FAILURE %s\n", ERR_VFS_DELETEDIR_01);
		return deletedir_FAILURE;
	}
	//"DIRECTORY_IS_NOT_EMPTY"
	if (curDir->child != NULL) {
		printf("deletedir_FAILURE %s\n", ERR_VFS_DELETEDIR_02);
		return deletedir_FAILURE;
	}

	/*
	    if (strcmp(parentDir->child->name, curDir->name) == 0)
		parentDir->child = curDir->rightSib;
	    else
		curDir->leftSib->rightSib = curDir->rightSib; //Reassigning pointers of doubly linked list

	    if (curDir->rightSib != NULL)
		curDir->rightSib->leftSib = curDir->leftSib;
    
	    curDir->rightSib = NULL;
	    curDir->leftSib = NULL;
	    curDir->parent = NULL;
	 */
	// setBlockFree(offset);
	//  curDir->parent = NULL;
	//   printf("Trucating Directory:");
	//  if (curDir->type == 'd')
	//     status = truncate(curDir->child); //Deleting every sub-dir of curDir.
	//  printf("Directory Completely Deleted!");

	//free(curDir);
	if (deleteNode(curDir) == 0) {
		offset = setFileDescriptorFree(curDir->fileDescOffset);
		deleteFile(curDir->name, curDir->fileDescOffset); //delete entry from hashtable
		delete_node(findPath(curDir));
		printf("deletedir_SUCCESS\n");
		//	free(curDir);
		return deletedir_SUCCESS;
	}
	printf("deletedir_FAILURE\n");
	return deletedir_FAILURE;
}


int moveDir(char* sourceDirPath, char* destDirPath) {

	int status = 0;
	//   printf("Moving Dir");

	if (mountStatus == unMounted) {
		printf("movedir_FAILURE %s\n", ERR_VFS_MOVEDIR_08);
		return movedir_FAILURE;
	}

	//CANNOT_FIND_SPECIFIED_SOURCEDIR
	if (invalidChar(sourceDirPath, 1)) {
		printf("movedir_FAILURE %s\n", ERR_VFS_MOVEDIR_01);
		return movedir_FAILURE;
	}
	//CANNOT_FIND_SPECIFIED_DESTINATIONDIR
	if (invalidChar(destDirPath, 1)) {
		printf("movedir_FAILURE %s\n", ERR_VFS_MOVEDIR_02);
		return movedir_FAILURE;
	}


	if(strcmp(sourceDirPath,"/")==0){
	printf("movedir_FAILURE %s\n", ERR_VFS_MOVEDIR_06);
	return movedir_FAILURE;
	}
	
	
	int len = strlen(sourceDirPath);
	int lenD = strlen(destDirPath);
	
	if(len>1 && sourceDirPath[len-1]=='/')
		sourceDirPath[len-1]='\0';

	if(lenD>1 && destDirPath[lenD-1]=='/')
		destDirPath[lenD-1]='\0';
	
	char * ptr = strstr(destDirPath, sourceDirPath);

	len = strlen(sourceDirPath);
	lenD = strlen(destDirPath);
/*
	printf("\t%s",destDirPath);
	printf("\t%s",sourceDirPath);

	exit(0);
*/
	
	if (ptr != NULL && strcmp(ptr, destDirPath) == 0 ) {//CANNOT_MOVE_PARENT_TO_CHILD_DIR
		if (strlen(destDirPath) >= len && destDirPath[len] == '/') {
			printf("movedir_FAILURE %s\n", ERR_VFS_MOVEDIR_06);
			return movedir_FAILURE;
		}
	}
	//if( strlen(destDirPath)>=(len+1))
	//printf("%c",destDirPath[len+1]);

	status = moveNode(sourceDirPath, destDirPath, 'd');
	if (status == 0) {
		printf("movedir_SUCCESS\n");
		return movedir_SUCCESS;
	} else if (status == 1) {//CANNOT_FIND_SPECIFIED_SOURCEDIR
		printf("movedir_FAILURE %s\n", ERR_VFS_MOVEDIR_01);
		return movedir_FAILURE;
	} else if (status == 2) {//CANNOT_FIND_SPECIFIED_DESTINATIONDIR
		printf("movedir_FAILURE %s\n", ERR_VFS_MOVEDIR_02);
		return movedir_FAILURE;
	} else if (status == 3) {//DESTINATION_ALREADY_HAVE_SOURCE_DIR
		printf("movedir_FAILURE %s \n", ERR_VFS_MOVEDIR_05);
		return movedir_FAILURE;
	} else if (status == 4) {//DESTINATION_CANNOT_BE_FILE
		printf("movedir_FAILURE %s \n", ERR_VFS_MOVEDIR_07);
		return movedir_FAILURE;
	} else if (status == 5) {//SOURCE_CANNOT_BE_FILE
		printf("movedir_FAILURE %s \n", ERR_VFS_MOVEDIR_04);
		return movedir_FAILURE;
	} else if (status == 6) {//VFS_NOT_MOUNTED
		printf("movedir FAILURE %s \n", ERR_VFS_MOVEDIR_01);
		return movedir_FAILURE;
	} else {//May be not able to open fileSystem
		printf("movedir_FAILURE\n");
		return movedir_FAILURE;
	}


}





//Function to output the traversal to file//

void structuredListFiles(FILE * ptr, directory * startNode) {
	directory *temp1 = startNode;
	directory *temp2 = startNode;

	if (temp1 != NULL) {

		if (temp1->child != NULL) {
			fprintf(ptr, "\nList of Directories/files inside : ");
			//  fprintf(ptr, "%s{%ld}", temp1->name, temp1->fileDescOffset);
			//fprintf(ptr, "%s", temp1->name);

			fprintf(ptr, "%s", findPath(temp1));
			fprintf(ptr, "\r\n\t\t");
			//    printf("%s\n", findPath(temp1));
			temp2 = temp1->child;
			while (temp2 != NULL) {

				fwrite(temp2->name, sizeof(char), strlen(temp2->name), ptr);
				//            fprintf(ptr, "{%ld}", temp2->fileDescOffset);
				//              printf("%s{%ld}", temp2->name, temp2->fileDescOffset);
				//	    printf("%s\n", findPath(temp2));
				fprintf(ptr, " # ");
				temp2 = temp2->rightSib;
			}
		}
		//if(temp1->type!='f')
		structuredListFiles(ptr, temp1->child);
		structuredListFiles(ptr, temp1->rightSib);

	}
}

// Function to list the subDirectories / files inside given directory

int listDir(char* pathOfCurDir, int isRecursiveSearchRequested, char *pathOfOutputFile) {

	FILE *ptr;
	directory *temp;
	iNode* inode = (iNode*) malloc(sizeof(iNode));
	inode->dirName = (char*) malloc(fileNameLength);

	if (mountStatus == unMounted || head == NULL) {
		printf("listdir_FAILURE %s\n", ERR_VFS_LISTDIR_03);
		return listdir_FAILURE;
	}

	if (invalidChar(pathOfCurDir, 1)) {
		printf("listdir_FAILURE %s\n", ERR_VFS_LISTDIR_01);
		return listdir_FAILURE;
	}

	char* path = (char*) malloc(strlen(pathOfCurDir) + 5);
	// INVALID_FLAG
	if (isRecursiveSearchRequested < 0 || isRecursiveSearchRequested > 1) {
		printf("listdir_FAILURE %s\n", ERR_VFS_LISTDIR_02);
		return listdir_FAILURE;
	}

	strcpy(path, pathOfCurDir);

	if (strcmp(pathOfCurDir, "/") == 0 && head != NULL)
		temp = head;
	else if (pathOfCurDir != NULL && strlen(pathOfCurDir) > 1) {
		if (traceIPath(pathOfCurDir, inode) == NULL) {
			printf("listdir_FAILURE %s\n", ERR_VFS_LISTDIR_01);
			return listdir_FAILURE;
		}
		temp = inode->parent;
	} else {
		printf("listdir_FAILURE %s\n", ERR_VFS_LISTDIR_01);
		return listdir_FAILURE;
	}
	//CANNOT_FIND_SPECIFIED_PATH_OR_DIR
	if (strcmp(getFileDirName(path), temp->name) != 0) {
		printf("listdir_FAILURE %s\n", ERR_VFS_LISTDIR_01);
		return listdir_FAILURE; // Dir not exists
	}

	//CANNOT_FIND_OUTPUTFILE
	if (pathOfOutputFile == NULL || strlen(pathOfOutputFile) == 0 || (ptr = fopen(pathOfOutputFile, "w")) == NULL) {
		printf("listdir_FAILURE %s\n", ERR_VFS_LISTDIR_04);
		return listdir_FAILURE;
	} else {
		if (isRecursiveSearchRequested == 0) {

			fprintf(ptr, "List of files inside : ");
			/*
				    if (temp->parent != NULL)
				  //      fprintf(ptr, "%s{%ld}", temp->parent->name, temp->parent->fileDescOffset);
					fprintf(ptr, "%s", temp->parent->name);
				    else
					fprintf(ptr, "Root");
			 */
			//		fprintf(ptr, "%s", temp->name);
			fprintf(ptr, "%s", findPath(temp));
			fprintf(ptr, "\r\n\t\t");
			//	   printf("%s\n", findPath(temp));
			while (temp != NULL) {

				fwrite(temp->name, sizeof(char), strlen(temp->name), ptr);
				//   fprintf(ptr, "{%ld}", temp->fileDescOffset);
				//    printf("%s{%ld}", temp->name, temp->fileDescOffset);
				//    printf("%s\n", findPath(temp));
				fprintf(ptr, " # ");

				temp = temp->rightSib;
			}
		} else if (isRecursiveSearchRequested == 1) {
			structuredListFiles(ptr, temp);
		}
		fclose(ptr);
		printf("listdir_SUCCESS\n");
		return listdir_SUCCESS;
	}
	printf("listdir_FAILURE\n");
	return listdir_FAILURE;
}


